package Socket.ChatRoom;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

public class ClientReceiver extends Thread {
	public static Socket server;
	public static BufferedReader in;
	public static PrintWriter out;
	public static SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss");
	public static String colorFlag = " color:";
	public static String exitFlag = "/exit";
	private MyWindow window;

	public ClientReceiver(MyWindow window, Socket s) {
		server = s;
		this.window = window;
		try {
			out = new PrintWriter(server.getOutputStream(), true);
			in = new BufferedReader(new InputStreamReader(
					server.getInputStream()));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public void run() {
		try {
			String str = "";
			while (true) {
				str = in.readLine();
				if (null == str || "null".equals(str)) {
					System.out.println("null received, connection closing...");
					break;
				}
				Color color = getColorInfo(str);
				str = str.split(colorFlag)[0];
				System.out.println(str);
				window.insertDocument(str + "\n", color);
				window.textPane.selectAll();
				if (!window.isFocused()) {
					new Thread() {
						public void run() {
							while(!window.isFocused()){
								try {
									window.setTitle("Message Arrive");
									Thread.sleep(500);
									window.setTitle("Please check...");
									Thread.sleep(500);
								} catch (InterruptedException e) {
									e.printStackTrace();
								}
							}
							window.setTitle("Chat Room");
							window.textfield.requestFocusInWindow();
						}
					}.start();
				}
			}
		} catch (SocketException se) {
			System.out
					.println("server lost " + server.getRemoteSocketAddress());
		} catch (Throwable e) {
			e.printStackTrace();
		} finally {
			closeServer();
		}
	}

	private Color getColorInfo(String str) {
		if (str.contains(colorFlag)) {
			String[] value = str.split(colorFlag);
			if (value.length == 2) {
				Integer colorNum = Integer.valueOf(value[1]);
				return new Color(colorNum);
			}
		}
		return Color.black;
	}

	public static void main(String[] args) {
		try {
			Socket server = null;
			while (server == null || server.isClosed()) {
				server = createServer();

				ExecutorService exe = Executors.newCachedThreadPool();
				MyWindow window = new MyWindow();
				ClientReceiver receiver = new ClientReceiver(window, server);
				exe.execute(receiver);
				window.setVisible(true);
			}
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

	private static Socket createServer() {
		Socket s = null;
		try {
			while (null == s) {
				try {
					s = new Socket("192.168.61.65", 8888);
				} catch (ConnectException e) {
					System.out.println("Failed to connect server at "
							+ sdf.format(new Date()));
					Thread.sleep(3000);
				}
			}
			System.out.println("I am at " + InetAddress.getLocalHost()
					+ "\nChat room " + s + " connected.");
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return s;
	}

	public static void closeServer() {
		try {
			if (!server.isClosed()) {
				System.out.println("server closing " + server);
				server.close();
				System.exit(0);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

class MyWindow extends JFrame {
	private static final long serialVersionUID = 1L;
	public JTextField textfield = new JTextField(36);
	public JTextPane textPane = new JTextPane();

	public MyWindow() {
		super("Chat Room");
		Container con = getContentPane();
		con.setLayout(new BorderLayout());
		textPane.setEditable(false);

		con.add(new JScrollPane(textPane), BorderLayout.CENTER);
		con.add(inputPanel(), BorderLayout.SOUTH);

		setBounds(400, 200, 600, 500);
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.out.println("window closing...");
				try {
					ClientReceiver.server.close();
				} catch (Throwable e1) {
					e1.printStackTrace();
				}
				System.exit(0);
			}
		});
	}

	private Component inputPanel() {
		JPanel panel = new JPanel();
		panel.setLayout(new GridLayout(1, 1));
		panel.add(textfield);
		textfield.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				String input = textfield.getText();
				ClientReceiver.out.println(input);
				if (ClientReceiver.exitFlag.equals(input)) {
					try {
						ClientReceiver.server.close();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					System.exit(0);
				}
				textfield.setText(null);
			}
		});
		return panel;
	}

	public void insertDocument(String text, Color textColor) {
		SimpleAttributeSet set = new SimpleAttributeSet();
		StyleConstants.setForeground(set, textColor);
		StyleConstants.setFontSize(set, 12);
		Document doc = textPane.getStyledDocument();
		try {
			doc.insertString(doc.getLength(), text, set);
		} catch (BadLocationException e) {
		}
	}

}
